package mongotesting

import (
	"context"
	"fmt"
	"testing"

	"go.mongodb.org/mongo-driver/bson"

	"go.mongodb.org/mongo-driver/mongo/options"

	"go.mongodb.org/mongo-driver/mongo"

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/client"
	"github.com/docker/go-connections/nat"
)

const (
	image         = "mongo:4.4"
	containerPort = "27017/tcp"
)

var mongoUri string

const defaultMongoUri = "mongodb://192.168.182.144:27017/?readPreference=primary&ssl=false"

func RunWithMongoInDocker(m *testing.M) int {
	client, err := client.NewClientWithOpts(client.WithHost("tcp://192.168.182.144:2345"))
	if err != nil {
		panic(err)
	}
	ctx := context.Background()
	container, err := client.ContainerCreate(
		ctx,
		&container.Config{
			Image: "mongo:4.4",
			ExposedPorts: nat.PortSet{
				containerPort: {},
			},
		},
		&container.HostConfig{
			PortBindings: map[nat.Port][]nat.PortBinding{
				containerPort: {{HostPort: "0"}},
			},
		},
		nil,

		nil,
		"",
	)
	if err != nil {
		panic(err)
	}
	defer func() {
		err = client.ContainerRemove(ctx, container.ID, types.ContainerRemoveOptions{Force: true})
		if err != nil {
			panic(err)
		}
	}()
	err = client.ContainerStart(ctx, container.ID, types.ContainerStartOptions{})
	if err != nil {
		panic(err)
	}
	inspect, err := client.ContainerInspect(ctx, container.ID)
	if err != nil {
		panic(err)
	}
	mongoUri = fmt.Sprintf("mongodb://192.168.182.144:%s/?readPreference=primary&ssl=false", inspect.NetworkSettings.Ports[containerPort][0].HostPort)
	return m.Run()
}

func NewClient(ctx context.Context) (*mongo.Client, error) {
	return mongo.Connect(ctx, options.Client().ApplyURI(mongoUri))
}

func NewDefaultCilent(ctx context.Context) (*mongo.Client, error) {
	return mongo.Connect(ctx, options.Client().ApplyURI(defaultMongoUri))
}

// SetupIndexes sets up indexes for the given database.
func SetupIndexes(c context.Context, d *mongo.Database) error {
	_, err := d.Collection("account").Indexes().CreateOne(c, mongo.IndexModel{
		Keys: bson.D{
			{Key: "open_id", Value: 1},
		},
		Options: options.Index().SetUnique(true),
	})
	if err != nil {
		return err
	}

	_, err = d.Collection("trip").Indexes().CreateOne(c, mongo.IndexModel{
		Keys: bson.D{
			{Key: "trip.accountid", Value: 1},
			{Key: "trip.status", Value: 1},
		},
		Options: options.Index().SetUnique(true).SetPartialFilterExpression(bson.M{
			"trip.status": 1,
		}),
	})
	return err
}
